﻿using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;

namespace UFrame
{
    [System.Serializable]
    public class DebugDataEx
    {
        public string account;
        public string playerName;
        public string devices;
        public string context;
        public string stackTrace;
    }

    public static class PLDebug
    {
        private static float mTimer;
        private static string mTimerStr;
        private static bool mIsSendServer;
        public static string url;
        public static bool recordLog = false;
        public static bool recordError = false;
        public static bool recordWarning = false;

        public static List<string> mLogList = new List<string>();
        private static List<int> errorRepetion = new List<int>();
        private static bool isInit = false;


        [RuntimeInitializeOnLoadMethod]
        static void Init()
        {
            if (isInit)
            {
                return;
            }

            isInit = true;
            errorRepetion.Clear();


            Application.logMessageReceived -= OnLogError;
            Application.logMessageReceived += OnLogError;
        }


        [RuntimeInitializeOnLoadMethod]
        static void HookDebug()
        {
#if UNITY_STANDALONE_WIN && PLHook
        if(Application.platform == RuntimePlatform.WindowsEditor){
            System.Type[] parAry = new System.Type [1];
            parAry[0] = typeof(object);
            var t1 = typeof(UnityEngine.Debug);
            var t2 = typeof(PLDebug);
                
            var method = t1.GetMethod("Log", parAry);
            MethodInfo miReplacement = t2.GetMethod("Log");
            MethodHooker hooker = new MethodHooker(miReplacement, method, null);
            hooker.Install();
                
            method = t1.GetMethod("LogError", parAry);
            miReplacement = t2.GetMethod("LogError");
            hooker = new MethodHooker(miReplacement, method, null);
            hooker.Install();
                
            method = t1.GetMethod("LogWarning", parAry);
            miReplacement = t2.GetMethod("LogWarning");
            hooker = new MethodHooker(miReplacement, method, null);
            hooker.Install();
                
        }

#endif
        }

        public static void Log(object s)
        {
            UnityEngine.Debug.Log(s);
        }

        public static void LogError(object s)
        {
            UnityEngine.Debug.LogError(s);
        }

        public static void LogWarning(object s)
        {
            UnityEngine.Debug.LogWarning(s);
        }


        public static void SendError(string condition, string stackTrace)
        {
            if (mIsSendServer)
            {
                if (string.IsNullOrEmpty(stackTrace))
                {
                    //获得当前栈信息
                    StringBuilder stack = new StringBuilder();
                    StackTrace st = new StackTrace();
                    StackFrame[] sfs = st.GetFrames();

                    for (int u = 0; u < sfs.Length; ++u)
                    {
                        System.Reflection.MethodBase mb = sfs[u].GetMethod();
                        string error = string.Format("[CALL STACK][{0}]: {1}.{2}", u, mb.DeclaringType.FullName,
                            mb.Name);
                        stack.AppendLine(error);
                    }


                    stackTrace = stack.ToString();
                }

                string allError = condition + stackTrace;
                //如果堆栈完全一样 就不再上报这个错误,判断长度 
                int stackLen = allError.Length;
                foreach (var item in errorRepetion)
                {
                    if (item == stackLen)
                    {
                        return;
                    }
                }


                DebugDataEx ex = new DebugDataEx();
                ex.stackTrace = stackTrace;
                ex.context = condition;
                ex.devices = SystemInfo.deviceName;
                errorRepetion.Add(stackLen);

                string json = JsonUtility.ToJson(ex);

                /*Debug.Log(SystemInfo.deviceName);
                Debug.Log("栈信息" + stackTrace);
                Debug.Log(condition);*/

                //发送消息
                //TODO Check 没有写发送消息代码
                SendHttp(json);
            }
        }

        private static void SendHttp(string json)
        {
            if (string.IsNullOrEmpty(url))
            {
                return;
            }

            UnityWebRequest r = new UnityWebRequest(url, "POST");
            byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
            r.uploadHandler = new UploadHandlerRaw(bodyRaw);
            r.downloadHandler = new DownloadHandlerBuffer();
            r.SetRequestHeader("Content-Type", "application/json");
            UnityWebRequestAsyncOperation async = r.SendWebRequest();
        }

        public static void OnLogError(string condition, string stackTrace, LogType type)
        {
            if (type == LogType.Error)
            {
                SendError(condition, stackTrace);
            }

            if (recordLog && type == LogType.Log)
            {
                mLogList.Add(condition + stackTrace);
            }

            if (recordError && type == LogType.Error)
            {
                mLogList.Add(condition + stackTrace);
            }

            if (recordWarning && type == LogType.Warning)
            {
                mLogList.Add(condition + stackTrace);
            }
        }

        [Conditional("PL_Debug"), Conditional("UNITY_EDITOR")]
        public static void BeginSample(string s)
        {
            if (UnityEngine.Profiling.Profiler.enabled)
            {
                UnityEngine.Profiling.Profiler.BeginSample(s);
            }
        }

        [Conditional("PL_Debug"), Conditional("UNITY_EDITOR")]
        public static void EndSample()
        {
            if (UnityEngine.Profiling.Profiler.enabled)
            {
                UnityEngine.Profiling.Profiler.EndSample();
            }
        }

        [Conditional("PL_Debug"), Conditional("UNITY_EDITOR")]
        public static void BeginTimer(string s)
        {
            mTimerStr = s;
            mTimer = Time.realtimeSinceStartup;
        }

        [Conditional("PL_Debug"), Conditional("UNITY_EDITOR")]
        public static void EndTimer()
        {
            Log(string.Format("{0}消耗时间: {1}", mTimerStr, Time.realtimeSinceStartup - mTimer));
        }
    }
}